Eye tracking
新建一个文件夹,命名为preprocess,然后在里面新建文件eyetracker.py文件。键入如下代码:
import cv2
class EyeTracker:
def __init__(self,faceCascadePath,eyeCascadePath):
# load the face and eye detector
self.faceCascade = cv2.CascadeClassifier(faceCascadePath)
self.eyeCascade = cv2.CascadeClassifier(eyeCascadePath)
def track(self,image):
# detect faces in the image and initialize the list of
# rectangles containing the faces and eyes
faceRects = self.faceCascade.detectMultiScale(image,
scaleFactor=1.1,minNeighbors=5,minSize=(30,30),
flags=cv2.CASCADE_SCALE_IMAGE)
rects = []
我们定义了一个EyeTracker类,然后定义构造函数__int__。我们的EyeTracker类有两个参数:faceCascadePath和eyeCascadePath。第一个是OpenCV中内置面部级联分类器(face cascade classifier)的路径。第二个是眼睛级联分类器(eye cascade classifier)的路径。
然后,我们使用cv2.CascadeClassifier函数从磁盘加载两个分类器。
接着,我们定义了用于在图像中找到眼睛的轨迹方法(track)。此方法仅接收一个参数,即包含要跟踪的面部和眼睛的图像。
然后我们调用faceCascade分类器的detectMultiScale方法。该方法向我们返回图像中每个面部的边界框位置(即,x,y,宽度和高度)。
然后,我们初始化一个矩形列表,用于包含图像中的面部和眼睛矩形。
现在我们的图像中的脸部区域已经找到了,让我们看看如何使用它们来找到眼睛:
# loop over the face bounding boxes
for (fX,fY,fW,fH) in faceRects:
# extract the face ROI and update the list of
# bounding boxes
faceROI = image[fY:fY + fH,fX:fX + fW]
rects.append((fX,fY,fX + fW,fY + fH))
# detect eyes in the face ROI
eyeRects = self.eyeCascade.detectMultiScale(faceROI,
scaleFactor=1.1,minNeighbors=10,
minSize=(20,20),
flags=cv2.CASCADE_SCALE_IMAGE)
# loop over the eye bounding boxes
for (eX,eY,eW,eH) in eyeRects:
# update the list of boounding boxes
rects.append((fX + eX,fY + eY,fX + eX + eW,fY + eY + eH))
# return the rectangles representing bounding
# boxes around the faces and eyes
return rects
然后,我们使用NumPy阵列切片从图像中提取面部感兴趣区域(ROI:region of interest)。faceROI变量现在包含面部的边界框区域。
最后,我们将矩形的(x,y)坐标附加到rects列表中供以后使用。
接下来,我们移到眼睛检测。这一次,我们调用了eyeCascade的detectMultiScale方法,该方法返回了出了眼睛出现在图像位置的列表。
我们使用了更大的minNeighbors值,因为眼睛级联(eye cascade)往往比其他分类器产生更多的误报。
注意:这些参数被硬编码到EyeTracker类中。如果您将此脚本应用于自己的图像和视频,则可能需要稍微调整一下以获得最佳效果。从scaleFactor变量开始,然后转到minNeighbors。
接着,我们在眼睛的边界框区域上循环,并更新边界框矩形列表。
最后,我们将边界框列表将返回给调用者。
文件目录

现在,我们将困难的部分已经完成。是时候通过创建eyetracking.py将各个部分粘合在一起了:
from preprocess import EyeTracker
import imutils
import argparse
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-f", "--face", required = True,
help = "path to where the face cascade resides")
ap.add_argument("-e", "--eye", required = True,
help = "path to where the eye cascade resides")
ap.add_argument("-v", "--video",
help = "path to the (optional) video file")
args = vars(ap.parse_args())
# construct the eye tracker
et = EyeTracker(args["face"],args["eye"])
首先,我们输入必要的包。我们将使用我们自定义EyeTracker类来查找图像中的面部和眼睛。用imutils,一组图像处理便利功能来帮助我们调整图像大小。最后,使用argparse进行命令行解析,并使用cv2进行OpenCV绑定。
然后,我们解析了我们的命令行参数:–face,这是我们的面部级联分类器(face cascade classifier)的路径,–eye,是我们眼睛级联分类器(eye cascade classifier)的路径。
和前面一样,创建一个可选参数–video,它指向磁盘上的视频文件。
最后,我们分别使用脸部和眼睛分类器的路径实例化我们的EyeTracker类。
# if a video path was not supplied, grab the reference
# to the gray
if not args.get("video"):
camera = cv2.VideoCapture(0)
# otherwise, load the video
else:
camera = cv2.VideoCapture(args["video"])
# keep looping
while True:
# grab the current frame
(grabbed,frame) = camera.read()
# if we are viewing a video and we did not grab a
# frame, then we have reached the end of the video
if args.get("video") and not grabbed:
break
如果未提供视频文件,在这种情况下,cv2.VideoCapture函数被告知使用系统的网络摄像头。否则,如果提供了视频文件的路径,则cv2.VideoCapture函数将打开视频文件并返回指向它的指针。
接着,我们开始在视频frame上循环。对相机调用read()会抓取视频中的下一帧。read方法返回一个元组,包含(1)表示frame是否被成功读取的布尔值,以及(2)frame本身。
然后,我们进行检查以确定视频是否到达尾部。我们仅在从文件中读取视频时才执行此检查。
现在我们拥有视频中的当前帧,可以执行面部和眼睛检测:
# resize the frame and convert it to grayscale
frame = imutils.resize(frame,width=300)
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
# detect faces and eyes in the image
rects = et.track(gray)
# loop over the face bounding boxes and draw them
for rect in rects:
cv2.rectangle(frame,(rect[0],rect[1]),
(rect[2],rect[3]),(0,255,0),2)
# show the tracked eyes and face
cv2.imshow("Tracking",frame)
# if the 'q' key is pressed, stop the loop
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()
为了使面部和眼睛检测更快,我们首先调整图像的大小,使其具有300像素的宽度。
然后,我们将其转换为灰度。转换为灰度倾向于提高级联分类器的准确性。
使用视频中的当前帧调用EyeTracker的track方法。然后,此方法返回与图像中的面部和眼睛对应的rects列表。
接着,我们开始在边界框矩形上循环,并使用cv2.rectangle函数绘制每个矩形,其中第一个参数是frame,第二个是边界框的起始(x,y)坐标,第三个是结束frame的(x,y)坐标,后面是框的颜色(绿色)和厚度(2个像素)。
然后我们显示检测到的面部和眼睛的frame。我们进行检查以确定用户是否按下了q键。如果用户这样做,那么循环就会终止。
最后,我们执行清理,其中释放相机指针并关闭OpenCV创建的所有窗口。
python eyetracking.py --face cascades\haarcascade_frontalface_default.xml --eye cascades\haarcascade_eye.xml
完整代码:
链接:https://pan.baidu.com/s/1nBBrbk0GD8pl2aF_sscbuA 提取码:wwpy
更多的参考:
Simple, accurate eye center tracking in OpenCV
;